/*
 * Copyright (C) 2020 The LINN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.juqimiao.linn.logging;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
import com.juqimiao.linn.config.FrameworkConfig;
import com.juqimiao.linn.interception.config.InterceptorProperties;
import com.juqimiao.linn.logging.config.LoggerPropeties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 日志操作抽象类。
 * <p>
 *     1. 通过 Logger.getLogger关联特定的日志实现。默认使用 {@link CommonLogger}。
 *     也可通过application.yml配置指定内置的Sl4j2实现，或使用自定义的实现。
 *     linn:
 *      config:
 *          logging:
 *              provider: com.juqimiao.linn.logging.Sl4j2Logger
 *              enabled: true
 *     只有当enabled设置为true，才会实际进行日志记录。
 *     2. 自定义实现Logger实现类。
 *     3. 如果使用Sl4j2请参考resource/logback-spring.xml的配置。
 *
 * </p>
 * @author Collin Cai
 */
public abstract class Logger {

    @Autowired
    private static LoggerPropeties properties;
    protected Class<?> targetClz;
    public Logger(Class<?> clz) {
        targetClz = clz;
    }

    public abstract void debug(String message);

    public abstract void debug(String message, Throwable throwable);

    public abstract void error(String message, Throwable throwable);

    public abstract void info(String message);

    public abstract void info(String message, Throwable throwable);

    public abstract void warn(String message);

    public abstract void warn(String message, Throwable throwable);

    public static boolean loggingEnabled = false;

    private static Logger cachedLogger = null;
    /**
     * 获取配置的Logger对象。
     *
     * @param clz 日志目标记录对象类型。
     * @return 一个Logger对象。
     */
    public static Logger getLogger(Class<?> clz) {
        /* Todo: User the strong cache here, it support remove, expire data from cache.*/
        Logger logger = null;
        if (cachedLogger == null || (cachedLogger instanceof NullLogger)) {
            try {
                logger = getRealLogger(clz);
                cachedLogger = logger;
            } catch (NullPointerException e) {
                logger = new NullLogger(clz);
                cachedLogger = logger;
            }
        } else {
            logger = cachedLogger;
        }
        return logger;
    }

    private static Logger getRealLogger(Class<?> clz) {
        Logger logger = new CommonLogger(clz);
        LoggerPropeties loggerPropeties = FrameworkConfig.getWrapper().getBean(LoggerPropeties.class);
        if (loggerPropeties.isEnabled() && loggerPropeties.getProvider() != null) {
            try {
                loggingEnabled = loggerPropeties.isEnabled();
                Class<?> loggerClz = loggerPropeties.getProvider();
                Constructor<?> constructor = loggerClz.getConstructor(clz.getClass());
                logger = (Logger) constructor.newInstance(clz);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return logger;
    }

    public static void refreshCache() {
        cachedLogger = null;
        loggingEnabled = FrameworkConfig.getWrapper().getBean(LoggerPropeties.class).isEnabled();
    }
}
